简介:format string attack 简单入门知识
Format string 漏洞定义:
控制的缓冲寄存器作为参数传递给printf或者相关函数可以执行任意内存地址的写入
简单来说就是软件使用了格式化字符串作为参数,且该格式化字符串来自外部输入
原理:
printf是c语言中少有的支持可变参数的库函数 即 函数的调用者可以自由的指定函数参数的数量和类型,被调用者无法知道在函数调用之前到底有多少参数被压入栈帧当中
printf()函数的一般形式为printf(“format”, 输出表列),其第一个参数就是格式化字符串,用来告诉程序以什么格式进行输出
利用:
1、打印内存
恶意用户 可以使用”%s”,”%x”来得到堆栈的数据
在format中填充足够的参数,那就可以控制printf打出储存在栈中的信息,计算好format在栈中的地址与所需leak的信息地址之差,就可以得到想要的数据
也可以使用%s构造指针,泄露指定地址中的内容
栈顶是第一个参数, 第二个参数的地址和第一个参数一样。由于我们可以通过输入来操控栈,我们可以输入一个地址,再让%s正好对应到这个地址,从而输出地址指向的字符串,实现任意地址读。
但是如果输入长度有限制,而且我们的输入位于printf的第几十个参数之外要怎么办呢?叠加%x显然不现实。因此我们需要用到格式化字符串的另一个特性。
格式化字符串可以使用一种特殊的表示形式来指定处理第n个参数,如输出第五个参数可以写为%4$s,第六个为%5$s,需要输出第n个参数就是%(n-1)$[格式化控制符]。
2、修改内存
%n:格式化字符会将已输出的字符数写入到对应参数的内存中
eg:1
2
3
4offset=5 payload=\x8c\x97\x04\x08%5$n 其中0804978c是.bss段的首地址,一个可写地址。
执行前该地址中的内容是0
执行后内容变为了4(计算了\x8c\x97\x04\x08这4个字符)
由于我们可以任意地址写,且程序里有system函数,因此我们可以直接选择劫持一个函数的got表项为system的plt表项,从而执行system(“/bin/sh”)。
eg:1
2
3
4
5
6
7printf_got = 0×08049778
system_plt = 0×08048320
payload = p32(printf_got)+”%”+str(system_plt-4)+”c%5$n” #p32(printf_got)占了4字节,所以system_plt要减去4
payload发送过去后再次发送”/bin/sh”就可以拿shell
防护:
RELRO是重定位表只读(Relocation Read Only)
重定位表即我们经常提到的ELF文件中的got表和plt表。
这两个表是为程序外部的函数和变量的重定位做准备的,外部函数的内存地址是第一次被调用时,会被填进got表中。got表可写将会给格式化字符串漏洞带来一个非常方便的利用方式,即修改got表
使用checksec 命令可以检查程序开启的保护 ELRO: Full RELR会使.got和.got.plt都无法被修改,这样试图通过漏洞劫持got表的行为都会被阻止